import base64
import json
import pickle

from django.http import JsonResponse
from django.shortcuts import render
from django.views.generic import View
from django_redis import get_redis_connection

from goods.models import GoodsSKU


class CartAddView(View):

    def post(self, request):
        # 1、获取前端数据，json类型
        data_dict = request.POST

        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = int(data_dict.get('sku_id'))
        count = int(data_dict.get('count'))
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count, selected]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            GoodsSKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated():
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、将商品id和数量写入hash
            conn.hincrby('sku_count_%d' % user.id, sku_id, int(count))
            # 6-3、判断selected的状态是否为True，如果为True将商品id写入set中
            if selected:
                conn.sadd('selected_%d' % user.id, sku_id)

            return JsonResponse({
                'res': 5
            })

        else:
            response = JsonResponse({
                'res': 5
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 7-4、判断当前的sku_id是否已经在字典中，存在，说明商品已经添加过一次，需要对数量进行累加.。sku_id是字典key值
            if sku_id in cart_dict:
                count += int(cart_dict[sku_id]['count'])
            # 7-5、将新数据保存在字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response


class CartShowView(View):

    def get(self, request):
        # 1、判断用户是否登录，不同登录状态用户获取不同数据
        user = request.user
        if user.is_authenticated():
            # 2、登录用户，从reids中获取数据
            # 2-1、连接redis
            conn = get_redis_connection('carts')
            # 2-2、获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 2-3、获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 2-4、将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }

        else:
            # 3、未登录，从cookie中获取数据
            # 3-1、获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 3-2、判断cookie数据是否存在，在写入cookie时指定过有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 3-3、存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4、根据获取到的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = GoodsSKU.objects.filter(id__in=sku_ids)
        # 给sku增加count值
        total_count = 0
        total_price = 0
        for sku in skus:
            # 购买的数量
            sku.count = cart_dict[sku.id]['count']
            # 购买商品的价格小计
            sku.amount = cart_dict[sku.id]['count'] * sku.price
            # 购买商品的总量累加
            total_count += cart_dict[sku.id]['count']
            # 购买商品的总价累加
            total_price += cart_dict[sku.id]['count'] * sku.price
        context = {'skus': skus, 'total_count': total_count, 'total_price': total_price}

        return render(request, 'cart.html', context)


class CartUpdateView(View):

    def post(self, request):
        # 1、获取前端数据，json类型
        data_dict = request.POST
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = int(data_dict.get('sku_id'))
        count = int(data_dict.get('count'))
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            GoodsSKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated():
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、修改商品id和数量
            conn.hset('sku_count_%d' % user.id, sku_id, int(count))
            # 6-3、修改set中选中状态的sku_id
            if selected:
                # selected 为True 添加
                conn.sadd('selected_%d' % user.id, sku_id)
            else:
                # selected 为False 删除
                conn.srem('selected_%d' % user.id, sku_id)
            # 获取修改后的数据
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            total_count = 0
            for key, value in sku_count.items():
                total_count += int(value)
            return JsonResponse({
                'res': 5,
                'total_count': total_count
            })

        else:

            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 7-5、将新数据更新到字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            total_count = 0
            for key, value in cart_dict.items():
                total_count += value['count']
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response = JsonResponse({
                'res': 5,
                'total_count': total_count
            })
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response


class CartDeleteView(View):

    def post(self, request):
        # 1、获取前端数据，json类型
        data_dict = request.POST
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = int(data_dict.get('sku_id'))
        # 4、验证数据
        # 4-2、验证商品是否存在
        try:
            GoodsSKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'res': 0})
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated():
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、将商品id和数量从hash删除 hdel
            conn.hdel('sku_count_%d' % user.id, sku_id)
            # 6-3、删除set数据 srem
            conn.srem('selected_%d' % user.id, sku_id)

            return JsonResponse({
                'res': 3
            })

        else:
            response = JsonResponse({
                'res':3
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                return response
            # 解码后的字典可能是空字典
            if cart_dict:
                # 7-5、删除字典中数据
                del cart_dict[sku_id]
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response
